///@file Tensor4.h
///@brief Declaration of the class representing a fourth order tensor
///@author Arnaud Duval
///@version 0.0
///@date 2010/02/26


#ifndef TENSOR4_H
#define TENSOR4_H

#include <assert.h>
#include <iostream>
#include "Tensor3.h"
#include "SymTensor2.h"

///@class Tensor4
///@brief Class defining a fourth order tensor

///A fourth order tensor is an array of third order tensors
class Tensor4
{
    private:
        ///@brief Array of third order tensors
        Tensor3 *t;
        ///@brief Dimension of the tensor
        unsigned int size;
    public:
        ///@brief Default constructor
        Tensor4();
        ///@brief Constructor giving the dimension
        Tensor4(unsigned int);
        ///@brief Copy constructor
        Tensor4(const Tensor4 &);
        ///@brief Copy constructor with temporary object
        Tensor4(Tensor4*);
        ///@brief Destructor
        ~Tensor4();
        ///@brief Return an identity
        Tensor4 Identity(unsigned int);
        ///@brief Overload of () operator
        double& operator()(unsigned int, unsigned int, unsigned int, unsigned int);
        ///@brief Overload of = operator
        Tensor4& operator = (const Tensor4);
        ///@brief Overload of = operator for temporary objects
        Tensor4& operator = (Tensor4*);
        ///@brief Overload of += operator
        void operator += (const Tensor4&);
        ///@brief Overload of -= operator
        void operator -= (const Tensor4&);
        ///@brief Overload of || operator : twice contracted product : A_ijkl B_kl
        Tensor2 operator||(Tensor2);

        ///@brief Overload of || operator : twice contracted product : A_ijkl B_kl
        friend Tensor2 operator ||(const Tensor4&, Tensor2&);
        ///@brief Overload of || operator : twice contracted product : A_ij B_ijkl
        friend Tensor2 operator ||(Tensor2&, const Tensor4&);
        ///@brief Overload of || operator : twice contracted product : A_ijkl B_kl
        friend Tensor2 operator ||(const Tensor4&, SymTensor2&);
        ///@brief Overload of || operator : twice contracted product : A_ij B_ijkl
        friend Tensor2 operator ||(SymTensor2&, const Tensor4&);
        ///@brief Overload of * operator : product A_ij B_kl
        friend Tensor4 operator *(Tensor2&, Tensor2&);
        ///@brief Overload of + operator : addition of 2 Tensor4
        friend Tensor4 operator +(const Tensor4&, const Tensor4&);
        ///@brief Overload of - operator : substraction of 2 Tensor4
        friend Tensor4 operator -(const Tensor4&, const Tensor4&);
        ///@brief Overload of * operator : product Tensor4 - scalar
        friend Tensor4 operator *(const Tensor4&, const double&);
        ///@brief Overload of * operator : product scalar - Tensor4
        friend Tensor4 operator *(const double&, const Tensor4&);
        ///@brief Overload of / operator : division by a scalar
        friend Tensor4 operator /(const Tensor4&, const double&);
        ///@brief A function to compute cross product A_ij B_kl because of a problem with operator *
        Tensor4 CrossProduct(Tensor2, Tensor2);
        
        ///@brief Overload of << operator
        friend std::ostream& operator<<(std::ostream &, const Tensor4&);
};

#endif